package org.jwebuilder;

import static org.jwebuilder.util.Constant.EMPTY_STRING;
import static org.jwebuilder.util.Constant.SLASH;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;
import org.apache.jcs.JCS;
import org.jwebuilder.parsers.TemplateParser;
import org.jwebuilder.parsers.TextParser;
import org.jwebuilder.parsers.XmlPageParser;

import com.google.inject.Module;

public class JWebuilderFilter implements Filter
{
	public static ServletContext Application;
	public static String RequestEncoding;
	public static String ResponseEncoding;
	public static String TemplateEncoding;
	public static boolean EnableTemplateCache = false;
	public static String TemplateSuffix;
	
	public static final String QUERY_STRING_TEMPLATE_ENCODING = "_JWebuilderTemplateEncoding_";
	public static final String QUERY_STRING_PARSE = "_JWebuilderParse_";
	public static final String QUERY_STRING_RESOURCE = "_JWebuilderResource_";

	private static final String CONTENT_TYPE_HTML = "text/html";
	private static final String CONTENT_TYPE_JAVASCRIPT = "text/javascript";
	private static final String CONTENT_TYPE_CSS = "text/css";

	public void init(FilterConfig filterConfig) throws ServletException
	{
		Application = filterConfig.getServletContext();
		RequestEncoding = filterConfig.getInitParameter("requestEncoding");
		ResponseEncoding = filterConfig.getInitParameter("responseEncoding");
		TemplateEncoding = filterConfig.getInitParameter("templateEncoding");
		EnableTemplateCache = Boolean.parseBoolean(filterConfig.getInitParameter("enableTemplateCache"));
		TemplateSuffix = filterConfig.getInitParameter("templateSuffix").toLowerCase();
		final String guiceModule = filterConfig.getInitParameter("guiceModule");

		JCS.setConfigFilename("/org/jwebuilder/jcs/JavaCachingSystem.Configuration");

		if(guiceModule != null)
		{
			try
			{
				GuiceContext.getInstance().addModule((Module)Class.forName(guiceModule).newInstance());
			}
			catch (Exception e)
			{
				throw new RuntimeException(e);
			}
		}
		GuiceContext.getInstance().createInjector();
	}

	@SuppressWarnings("unchecked")
	public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
			throws IOException, ServletException
	{
		// Set request or response`s Character Encoding
    	if(RequestEncoding != null)
    	{
    		servletRequest.setCharacterEncoding(RequestEncoding);
    	}
    	if(ResponseEncoding != null)
    	{
    		servletResponse.setCharacterEncoding(ResponseEncoding);
    	}

    	final HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
    	final HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
    	final String contextPath = httpServletRequest.getContextPath();
    	String requestURI = httpServletRequest.getRequestURI();
    	if(!contextPath.equals(EMPTY_STRING) && !contextPath.equals(SLASH))
    	{
    		requestURI = requestURI.substring(contextPath.length());
    	}
    	final String filePath = Application.getRealPath(requestURI);
    	File file = new File(filePath);

		// 通过查询字符串指定的模板编码
		final String templateEncoding = httpServletRequest.getParameter(QUERY_STRING_TEMPLATE_ENCODING);
		// 通过查询字符串指定请求的 JavaScript 或 CSS 是否需要进行解析
		final boolean jWebuilderParse = Boolean.parseBoolean(httpServletRequest.getParameter(QUERY_STRING_PARSE));
		// 通过查询字符串指定请求的 JavaScript 或 CSS 是否为 ClassPath 中的资源文件
		final boolean jWebuilderResource = Boolean.parseBoolean(httpServletRequest.getParameter(QUERY_STRING_RESOURCE));

    	if(requestURI.toLowerCase().endsWith(TemplateSuffix))
    	{
    		if(jWebuilderResource)
    		{
    			TemplateParser templateParser = GuiceContext.getInstance().getInjector().getInstance(TemplateParser.class);
    			templateParser.setPageId(XmlPageParser.XML_PAGE_ID_PREFIX + requestURI);
	    		final String result = templateParser.parse(IOUtils.toString(JWebuilderFilter.class.getResourceAsStream(requestURI), (templateEncoding == null ? TemplateEncoding : templateEncoding)), null, new HashMap<String, Object>(httpServletRequest.getParameterMap()), (templateEncoding == null ? TemplateEncoding : templateEncoding));
	    		if(result != null)
	    		{
		    		httpServletResponse.setContentType(CONTENT_TYPE_HTML);
		    		httpServletResponse.getWriter().print(result);
		    		httpServletResponse.getWriter().flush();
	    		}
    		}
    		else if(file != null && file.isFile())
        	{
    			XmlPageParser templateParser = (XmlPageParser) GuiceContext.getInstance().getInjector().getInstance(TemplateParser.class);
    			templateParser.setPageId(XmlPageParser.XML_PAGE_ID_PREFIX + requestURI);
    			final String result = templateParser.parse(file, null, new HashMap<String, Object>(httpServletRequest.getParameterMap()), (templateEncoding == null ? TemplateEncoding : templateEncoding));
    			if(result != null)
	    		{
	    			httpServletResponse.setContentType(CONTENT_TYPE_HTML);
		    		httpServletResponse.getWriter().print(result);
		    		httpServletResponse.getWriter().flush();
	    		}
        	}
    		else
    		{
    			filterChain.doFilter(servletRequest, servletResponse);
    		}
    	}
    	else if(requestURI.toLowerCase().endsWith(".js"))
    	{
			if(jWebuilderResource)
			{
				final String fileText = IOUtils.toString(JWebuilderFilter.class.getResourceAsStream(requestURI), (templateEncoding == null ? TemplateEncoding : templateEncoding));
				if(jWebuilderParse)
				{
    				// 解析 JavaScript 模板（使用查询字符串参数作为数据变量）
    				final String result = TextParser.parse(fileText, null, new HashMap<String, Object>(httpServletRequest.getParameterMap()));
    	    		httpServletResponse.setContentType(CONTENT_TYPE_JAVASCRIPT);
    	    		httpServletResponse.getWriter().print(result);
    	    		httpServletResponse.getWriter().flush();
				}
				else
				{
					httpServletResponse.setContentType(CONTENT_TYPE_JAVASCRIPT);
    	    		httpServletResponse.getWriter().print(fileText);
    	    		httpServletResponse.getWriter().flush();
				}
			}
			else if(file != null && file.isFile())
			{
				if(jWebuilderParse)
				{
    				// 解析 JavaScript 模板（使用查询字符串参数作为数据变量）
    				final String result = TextParser.parse(file, null, new HashMap<String, Object>(httpServletRequest.getParameterMap()), (templateEncoding == null ? TemplateEncoding : templateEncoding));
    	    		httpServletResponse.setContentType(CONTENT_TYPE_JAVASCRIPT);
    	    		httpServletResponse.getWriter().print(result);
    	    		httpServletResponse.getWriter().flush();
				}
				else
				{
					filterChain.doFilter(servletRequest, servletResponse);
				}
			}
			else
    		{
    			filterChain.doFilter(servletRequest, servletResponse);
    		}
    	}
    	else if(requestURI.toLowerCase().endsWith(".css"))
    	{
    		if(jWebuilderResource)
			{
				final String fileText = IOUtils.toString(JWebuilderFilter.class.getResourceAsStream(requestURI), (templateEncoding == null ? TemplateEncoding : templateEncoding));
				if(jWebuilderParse)
				{
    				// 解析 JavaScript 模板（使用查询字符串参数作为数据变量）
    				final String result = TextParser.parse(fileText, null, new HashMap<String, Object>(httpServletRequest.getParameterMap()));
    	    		httpServletResponse.setContentType(CONTENT_TYPE_CSS);
    	    		httpServletResponse.getWriter().print(result);
    	    		httpServletResponse.getWriter().flush();
				}
				else
				{
					httpServletResponse.setContentType(CONTENT_TYPE_CSS);
    	    		httpServletResponse.getWriter().print(fileText);
    	    		httpServletResponse.getWriter().flush();
				}
			}
			else if(file != null && file.isFile())
			{
				if(jWebuilderParse)
				{
    				// 解析 JavaScript 模板（使用查询字符串参数作为数据变量）
    				final String result = TextParser.parse(file, null, new HashMap<String, Object>(httpServletRequest.getParameterMap()), (templateEncoding == null ? TemplateEncoding : templateEncoding));
    	    		httpServletResponse.setContentType(CONTENT_TYPE_CSS);
    	    		httpServletResponse.getWriter().print(result);
    	    		httpServletResponse.getWriter().flush();
				}
				else
				{
					filterChain.doFilter(servletRequest, servletResponse);
				}
			}
			else
    		{
    			filterChain.doFilter(servletRequest, servletResponse);
    		}
    	}
    	else
    	{
    		filterChain.doFilter(servletRequest, servletResponse);
    	}
	}

	public void destroy()
	{
		
	}
}